package org.de.maeyer.statistic;

import static java.lang.Double.*;


/**
 * Accumulates count, mean and variance. The algorithm is both efficient and of high numerical stability.
 * 
 * @author Peter De Maeyer
 * @see http://planetmath.org/encyclopedia/OnePassAlgorithmToComputeSampleVariance.html
 * @see http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
 */
public class VarianceAccumulator implements Accumulator {

	private long count;

	private double mean;

	private double residual;

	public VarianceAccumulator(long count, double mean, double residual) {
		this.count = count;
		this.mean = mean;
		this.residual = residual;
	}

	public VarianceAccumulator() {
		this(0L, NaN, NaN);
	}

	@Override
	public void reset() {
		count = 0L;
		mean = NaN;
		residual = NaN;
	}
	
	@Override
	public void accumulate() {
	    throw new UnsupportedOperationException();
	}

	@Override
	public void accumulateDouble(double value) {
		if (count++ == 0L) { // This expression updates the count.
			mean = value;
			residual = 0.;
		} else {
			double delta = value - mean;
			mean += delta / count; // This expression uses the updated count.
			residual += delta * (value - mean); // This expression uses the updated mean.
		}
	}
	
	@Override
	public void accumulateLong(long value) {
	    accumulateDouble(value);
	}
	
	@Override
	public void accumulateObject(Object value) {
	    accumulateDouble(((Number) value).doubleValue());
	}
	
	@Override
	public void appendTo(StatisticsBuilder builder) {
		builder.setVariance(count, mean, residual);
	}
}
